package com.kamistoat.meimeichat.meimeichatserverapplication.netty.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kamistoat.meimeichat.meimeichatserverapplication.entity.*;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.service.NettyUserService;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.utils.NettyConstants;
import com.kamistoat.meimeichat.meimeichatserverapplication.netty.utils.NettySocketChannelUtil;
import com.kamistoat.meimeichat.meimeichatserverapplication.service.*;
import com.kamistoat.meimeichatserveraggrement.protocol.friend.dto.UserDto;
import com.kamistoat.meimeichatserveraggrement.protocol.login.LoginResponse;
import com.kamistoat.meimeichatserveraggrement.protocol.login.dto.*;
import com.kamistoat.meimeichatserveraggrement.protocol.talk.TalkNoticeResponse;
import io.netty.channel.Channel;
import lombok.extern.flogger.Flogger;
import org.apache.catalina.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service("nettyUserService")
public class NettyUserServiceImpl implements NettyUserService {
    @Autowired
    MmcUserService mmcUserService;
    @Autowired
    MmcGroupsService mmcGroupsService;
    @Autowired
    MmcTalkBoxService mmcTalkBoxService;
    @Autowired
    MmcChatRecordService mmcChatRecordService;
    @Autowired
    MmcUserFriendService mmcUserFriendService;
    @Autowired
    MmcUserGroupService mmcUserGroupService;

    @Qualifier(value = "nettyThreadPoolExecutor")
    @Autowired
    ThreadPoolExecutor nettyThreadPoolExecutor;

    /**
     * 获取 LoginResponse
     *
     * @param channel
     * @param selfUserEntity
     */
    @Override
    public LoginResponse getLoginResponse(Channel channel, MmcUserEntity selfUserEntity) {
        // 2. 记录在线用户channel
        // 2.1 添加在线用户通信管道. 首先确保不存在之前的污染通道(即限制唯一登录实例)
        NettySocketChannelUtil.removeUserChannelByUserId(selfUserEntity.getUserId());
        NettySocketChannelUtil.addChannel(selfUserEntity.getUserId(), channel);

        // 用户群组列表。只返回自己仍加入其中的群组
        List<GroupsDto> groupsDtoList = queryUserGroupsList(selfUserEntity.getUserId());
        // 2.2 添加群组成员通信管道
        // 原项目按照群组来维护。为每一个群组维护一个channel列表。当群组内有成员登录时，将成员channel添加列表
        for (GroupsDto groupsDto : groupsDtoList) {
            NettySocketChannelUtil.removeChannelGroupByUserId(groupsDto.getGroupId(), selfUserEntity.getUserId());
            NettySocketChannelUtil.addChannelGroup(groupsDto.getGroupId(), channel);
        }

        // 3. 组装消息反馈给Client，用以在客户端进行显示.. 用户信息、用户对话框列表、好友列表、群组列表
        // 组装消息包
        LoginResponse loginResponse = new LoginResponse();
        loginResponse.setUserId(selfUserEntity.getUserId());
        loginResponse.setUserNickName(selfUserEntity.getUserNickname());
        loginResponse.setUserHead(selfUserEntity.getUserHead());

        // 3.1 用户的群组信息.
        loginResponse.setGroupsList(groupsDtoList);

        // 用户好友列表。返回所有好友，无论是否删除
        List<UserFriendDto> userFriendDtoList = queryUserFriendInfoList(selfUserEntity.getUserId());
        // 3.2 用户好友信息.
        loginResponse.setUserFriendList(userFriendDtoList);

        // 3.3 获取所有处于展开状态的聊天框，就像微信一样每次登录时显示出与他人的聊天内容
        // 同样转换为 专门用于网络间传输的 ChatTalkDto，同时需要包含该聊天框对应的聊天记录
        List<MmcTalkBoxEntity> talkBoxEntityList = queryTalkBoxInfoList(selfUserEntity.getUserId());
        // P.S. 由于聊天记录是双向的，为了保证总是获取最新的消息，不要提前查，处理一个对话框查一遍聊天记录
        // TODO 但仍无法解决一致性问题，核心问题就是数据渲染期间好友发来消息咋办。消息时间戳同步？或者聊天记录存在本地，每次登录从本地拿然后去服务器拿离线期间的聊天记录？
        List<ChatTalkDto> chatTalkDtoList = new ArrayList<>();
        // 对每一个对话框进行处理
        for (MmcTalkBoxEntity mmcTalkBoxEntity : talkBoxEntityList) {
            // 私聊和群聊要分开处理
            // 3.3.1 好友私聊
            if (mmcTalkBoxEntity.getTalkType().equals(NettyConstants.TalkType.Friend.getCode())) {
                // 获取当前聊天框对应的好友详情. 注意，聊天框存在和陌生人聊天的情况
                List<UserFriendDto> weatherFriend = userFriendDtoList.stream()
                        .filter(friend -> friend.getFriendId().equals(mmcTalkBoxEntity.getTalkId()))
                        .collect(Collectors.toList());
                UserFriendDto cur_talk_friend = null;
                if (weatherFriend.size() > 0) {
                    // 如果当前聊天框是和好友聊，则直接套用好友的信息
                    cur_talk_friend = weatherFriend.get(0);
                } else {
                    // 否则是和陌生人聊天，则先去查询陌生人信息
                    cur_talk_friend = queryUserDto(mmcTalkBoxEntity.getTalkId());
                    cur_talk_friend.setRelationStatus(NettyConstants.FriendRelationType.Foreign.getCode());
                }
                // 构建一个对话框Dto
                ChatTalkDto chatTalkDto = getFriendChatTalkDto(selfUserEntity, mmcTalkBoxEntity, cur_talk_friend);
                if (chatTalkDto == null) continue;

                chatTalkDtoList.add(chatTalkDto);
            }
            // 3.3.2 群组聊天
            else {
                // 可以保证，一定能从当前有效群组中找出聊天框对应的群组
                GroupsDto cur_talk_group = groupsDtoList.stream()
                        .filter(groupsDto -> groupsDto.getGroupId().equals(mmcTalkBoxEntity.getTalkId()))
                        .collect(Collectors.toList())
                        .get(0);
                // 构建一个对话框Dto
                ChatTalkDto chatTalkDto = getGroupChatTalkDto(selfUserEntity, userFriendDtoList, mmcTalkBoxEntity, cur_talk_group);
                if (chatTalkDto == null) continue;

                chatTalkDtoList.add(chatTalkDto);
            }
        }
        loginResponse.setChatTalkList(chatTalkDtoList);

        // 3.4 获取所有在线好友的P2P地址
        // 由于Map本身也只是保存在线用户，所以并不需要在服务端做区分
        ArrayList<ClientAddressDto> friendAddressList = new ArrayList<>();
        for (UserFriendDto userFriendDto : userFriendDtoList) {
            InetSocketAddress friendP2PAddress = NettySocketChannelUtil.USER_ID_P2P_ADDRESS_MAP.get(userFriendDto.getFriendId());
            if(friendP2PAddress != null){
                String[] split = friendP2PAddress.toString().split(":");
                ClientAddressDto clientAddressDto = new ClientAddressDto();
                clientAddressDto.setWantedUserId(userFriendDto.getFriendId());
                clientAddressDto.setWantedUserHost(split[0].substring(1));
                clientAddressDto.setWantedUserPort(Integer.parseInt(split[1]));
                friendAddressList.add(clientAddressDto);
            }
        }
        loginResponse.setFriendAddressList(friendAddressList);

        loginResponse.setSuccess(true);
        return loginResponse;
    }

    /**
     * 获取私聊对话框Dto
     *
     * @param selfUserEntity   自身Entity
     * @param mmcTalkBoxEntity 对话框Entity
     * @param cur_talk_friend  好友Entity
     */
    private ChatTalkDto getFriendChatTalkDto(MmcUserEntity selfUserEntity, MmcTalkBoxEntity mmcTalkBoxEntity, UserFriendDto cur_talk_friend) {
        ChatTalkDto chatTalkDto = new ChatTalkDto();
        // 记录基础信息
        chatTalkDto.setTalkType(NettyConstants.TalkType.Friend.getCode());
        chatTalkDto.setTalkId(mmcTalkBoxEntity.getTalkId());
        chatTalkDto.setTalkName(cur_talk_friend.getFriendName());
        chatTalkDto.setTalkHead(cur_talk_friend.getFriendHead());
        chatTalkDto.setTalkDate(mmcTalkBoxEntity.getUpdateTime());

        // 获取私聊对话框中的聊天记录Dto列表
        List<ChatRecordDto> chatRecordDtoList = getFriendChatRecordDtos(selfUserEntity, mmcTalkBoxEntity, cur_talk_friend);
        if (chatRecordDtoList == null) return null;

        chatTalkDto.setTalkSketch(chatRecordDtoList.get(0).getMsgContent());
        chatTalkDto.setChatRecordList(chatRecordDtoList);
        return chatTalkDto;
    }

    /**
     * 获取私聊对话框中的聊天记录Dto列表
     *
     * @param selfUserEntity   自身Entity
     * @param mmcTalkBoxEntity 对话框Entity
     * @param cur_talk_friend  好友Entity
     */
    private List<ChatRecordDto> getFriendChatRecordDtos(MmcUserEntity selfUserEntity, MmcTalkBoxEntity mmcTalkBoxEntity, UserFriendDto cur_talk_friend) {
        // 查询聊天记录列表，既要查自己发给好友的，也要查好友发给自己的
        List<MmcChatRecordEntity> cur_record_list =
                queryUserFriendChatRecord(mmcTalkBoxEntity.getUserId(), mmcTalkBoxEntity.getTalkId());
        if (cur_record_list == null || cur_record_list.size() == 0) {
            return null;
        }
        // 对每一条聊天记录，转换为 网络传输专用的 ChatRecordDto
        return cur_record_list.stream()
                .map(single_record -> {
                    ChatRecordDto chatRecordDto = new ChatRecordDto();
                    chatRecordDto.setTalkId(mmcTalkBoxEntity.getTalkId());
                    chatRecordDto.setMsgType(single_record.getMsgType());
                    chatRecordDto.setMsgContent(single_record.getMsgContent());
                    chatRecordDto.setMsgDate(single_record.getMsgDate());
                    if (single_record.getUserId().equals(selfUserEntity.getUserId())) {
                        // 自己发送的消息，MsgUserType=0
                        chatRecordDto.setMsgUserType(NettyConstants.MsgUserType.Myself.getCode());
                        chatRecordDto.setSenderId(single_record.getUserId());
                        chatRecordDto.setSenderNickName(selfUserEntity.getUserNickname());
                        chatRecordDto.setSenderHead(selfUserEntity.getUserHead());
                    } else {
                        // 好友发送的消息，MsgUserType=1
                        chatRecordDto.setMsgUserType(NettyConstants.MsgUserType.Friend.getCode());
                        chatRecordDto.setSenderId(single_record.getUserId());
                        chatRecordDto.setSenderNickName(cur_talk_friend.getFriendName());
                        chatRecordDto.setSenderHead(cur_talk_friend.getFriendHead());
                    }
                    return chatRecordDto;
                })
                .sorted((o1, o2) -> o2.getMsgDate().compareTo(o1.getMsgDate()))
                .collect(Collectors.toList());
    }

    /**
     * 获取群组对话框Dto
     *
     * @param selfUserEntity    自身Entity
     * @param userFriendDtoList 自身好友Dto列表
     * @param mmcTalkBoxEntity  对话框Entity
     * @param cur_talk_group    当前群组Dto
     */
    private ChatTalkDto getGroupChatTalkDto(MmcUserEntity selfUserEntity, List<UserFriendDto> userFriendDtoList, MmcTalkBoxEntity mmcTalkBoxEntity, GroupsDto cur_talk_group) {
        ChatTalkDto chatTalkDto = new ChatTalkDto();
        // 记录基础信息
        chatTalkDto.setTalkType(NettyConstants.TalkType.Group.getCode());
        chatTalkDto.setTalkId(mmcTalkBoxEntity.getTalkId());
        chatTalkDto.setTalkName(cur_talk_group.getGroupName());
        chatTalkDto.setTalkHead(cur_talk_group.getGroupHead());
        chatTalkDto.setTalkDate(mmcTalkBoxEntity.getUpdateTime());

        // 获取群组聊天框中的聊天消息Dto列表
        List<ChatRecordDto> chatRecordDtoList = getGroupChatRecordDtos(selfUserEntity, userFriendDtoList, mmcTalkBoxEntity);
        if (chatRecordDtoList == null) return null;

        chatTalkDto.setTalkSketch(chatRecordDtoList.get(0).getMsgContent());
        chatTalkDto.setChatRecordList(chatRecordDtoList);
        return chatTalkDto;
    }

    /**
     * 获取群组聊天框中的聊天消息Dto列表
     *
     * @param selfUserEntity    自身Entity
     * @param userFriendDtoList 自身好友Dto列表
     * @param mmcTalkBoxEntity  对话框Entity
     */
    private List<ChatRecordDto> getGroupChatRecordDtos(MmcUserEntity selfUserEntity, List<UserFriendDto> userFriendDtoList, MmcTalkBoxEntity mmcTalkBoxEntity) {
        // 查询群组聊天记录，包括该群组中所有成员发送的消息
        List<MmcChatRecordEntity> cur_record_list =
                queryUserGroupChatRecord(mmcTalkBoxEntity.getUserId(), mmcTalkBoxEntity.getTalkId());
        if (cur_record_list == null || cur_record_list.size() == 0) {
            return null;
        }
        // 对每一条聊天记录，转换为 网络传输专用的 ChatRecordDto
        return cur_record_list.stream()
                .map(single_record -> {
                    ChatRecordDto chatRecordDto = new ChatRecordDto();
                    chatRecordDto.setTalkId(mmcTalkBoxEntity.getTalkId());
                    chatRecordDto.setMsgType(single_record.getMsgType());
                    chatRecordDto.setMsgContent(single_record.getMsgContent());
                    chatRecordDto.setMsgDate(single_record.getMsgDate());
                    if (single_record.getUserId().equals(selfUserEntity.getUserId())) {
                        // 自己发送的消息，MsgUserType=0
                        chatRecordDto.setMsgUserType(NettyConstants.MsgUserType.Myself.getCode());
                        chatRecordDto.setSenderId(single_record.getUserId());
                        chatRecordDto.setSenderNickName(selfUserEntity.getUserNickname());
                        chatRecordDto.setSenderHead(selfUserEntity.getUserHead());
                    } else {
                        // 群组其他成员发送的消息，MsgUserType=1
                        chatRecordDto.setMsgUserType(NettyConstants.MsgUserType.Friend.getCode());
                        chatRecordDto.setSenderId(single_record.getUserId());
                        // 群组中的好友不一定是自己的好友，因此可能需要再去数据库中查该用户的信息
                        List<UserFriendDto> groupFriends = userFriendDtoList.stream()
                                .filter(friend -> friend.getFriendId().equals(single_record.getUserId()))
                                .collect(Collectors.toList());
                        if (groupFriends.size() > 0) {
                            chatRecordDto.setSenderNickName(groupFriends.get(0).getFriendName());
                            chatRecordDto.setSenderHead(groupFriends.get(0).getFriendHead());
                        } else {
                            MmcUserEntity strangerFriend = queryUserInfo(single_record.getUserId());
                            chatRecordDto.setSenderNickName(strangerFriend.getUserNickname());
                            chatRecordDto.setSenderHead(strangerFriend.getUserHead());
                        }
                    }
                    return chatRecordDto;
                })
                .sorted(Comparator.comparing(ChatRecordDto::getMsgDate))
                .collect(Collectors.toList());
    }

    /**
     * 根据userId查询用户详情并制作成UserDto
     *
     * @param userId
     * @return
     */
    private UserFriendDto queryUserDto(String userId) {
        MmcUserEntity mmcUserEntity = queryUserInfo(userId);
        UserFriendDto userFriendDto = new UserFriendDto();
        userFriendDto.setFriendId(mmcUserEntity.getUserId());
        userFriendDto.setFriendName(mmcUserEntity.getUserNickname());
        userFriendDto.setFriendHead(mmcUserEntity.getUserHead());
        return userFriendDto;
    }

    /**
     * 根据UserId查询用户详情
     *
     * @param userId
     */
    @Override
    public MmcUserEntity queryUserInfo(String userId) {
        return mmcUserService.getOne(new QueryWrapper<MmcUserEntity>().eq("user_id", userId));
    }

    /**
     * 根据Nickname查询用户详情
     *
     * @param userNickname
     */
    @Override
    public MmcUserEntity queryUserInfoByNickname(String userNickname) {
        return mmcUserService.getOne(new QueryWrapper<MmcUserEntity>().eq("user_nickname", userNickname));
    }

    /**
     * 添加好友关系
     *
     * @param userFriendList
     */
    @Override
    public void addUserFriend(ArrayList<MmcUserFriendEntity> userFriendList) {
        for (MmcUserFriendEntity mmcUserFriendEntity : userFriendList) {
            mmcUserFriendEntity.setId(null);
            mmcUserFriendEntity.setCreateTime(new Date());
            mmcUserFriendEntity.setUpdateTime(new Date());
        }
        mmcUserFriendService.saveBatch(userFriendList);
    }

    /**
     * 收起对话框。下次用户登陆后不会展开已收起的聊天框.就是将对话框的显示状态改为1
     *
     * @param userId
     * @param talkId
     */
    @Override
    public void deleteUserTalk(String userId, String talkId) {
        MmcTalkBoxEntity existedOne =
                mmcTalkBoxService.getOne(new QueryWrapper<MmcTalkBoxEntity>().eq("user_id", userId).eq("talk_id", talkId));
        if (existedOne != null) {
            existedOne.setShowStatus(NettyConstants.TalkBoxShowStatus.STACK.getCode());
            mmcTalkBoxService.updateById(existedOne);
        }
    }

    /**
     * 删除聊天记录.
     * 当传入两个用户Id时，代表删除两人之间的所有聊天记录。
     * 当传入 “group” + 群组Id时，代表群组被删除，则删除该群组的所有聊天记录
     *
     * @param userId
     * @param talkId
     */
    @Override
    public void deleteUserTalkRecord(String userId, String talkId) {
        mmcChatRecordService.remove(new QueryWrapper<MmcChatRecordEntity>().eq("user_id", userId).eq("friend_id", talkId));
    }

    /**
     * 根据UserId查询其好友的详细信息
     * 查询全部好友，包括已删除的好友。因为像QQ那样，删除好友只是解除好友关系，但是聊天记录保留
     *
     * @param userId
     * @return
     */
    @Override
    public List<UserFriendDto> queryUserFriendInfoList(String userId) {
        // user-friend关系
        List<MmcUserFriendEntity> userFriendEntityList =
                mmcUserFriendService.list(new QueryWrapper<MmcUserFriendEntity>().eq("user_id", userId));
        // 正常friendId
        List<String> normalFriendIdList = userFriendEntityList.stream()
                .filter(userFriend -> userFriend.getRelationStatus().equals(NettyConstants.FriendRelationType.Normal.getCode()))
                .map(MmcUserFriendEntity::getUserFriendId).collect(Collectors.toList());
        // 已删除friendId
        List<String> deletedFriendIdList = userFriendEntityList.stream()
                .filter(userFriend -> userFriend.getRelationStatus().equals(NettyConstants.FriendRelationType.Deleted.getCode()))
                .map(MmcUserFriendEntity::getUserFriendId).collect(Collectors.toList());
        // 已拉黑friendId
        List<String> blockedFriendIdList = userFriendEntityList.stream()
                .filter(userFriend -> userFriend.getRelationStatus().equals(NettyConstants.FriendRelationType.Blocked.getCode()))
                .map(MmcUserFriendEntity::getUserFriendId).collect(Collectors.toList());

        List<UserFriendDto> userFriendDtoList = new ArrayList<>();
        uIds2UFDtoList(normalFriendIdList, userFriendDtoList, NettyConstants.FriendRelationType.Normal.getCode());
        uIds2UFDtoList(deletedFriendIdList, userFriendDtoList, NettyConstants.FriendRelationType.Deleted.getCode());
        uIds2UFDtoList(blockedFriendIdList, userFriendDtoList, NettyConstants.FriendRelationType.Blocked.getCode());
        return userFriendDtoList;
    }

    private void uIds2UFDtoList(List<String> friendIdList, List<UserFriendDto> userFriendDtoList, int relationStatus) {
        if (friendIdList == null || friendIdList.size() == 0) {
            return;
        }
        for (MmcUserEntity mmcUserEntity : mmcUserService.list(new QueryWrapper<MmcUserEntity>().in("user_id", friendIdList))) {
            UserFriendDto userFriendDto = new UserFriendDto();
            userFriendDto.setFriendId(mmcUserEntity.getUserId());
            userFriendDto.setFriendName(mmcUserEntity.getUserNickname());
            userFriendDto.setFriendHead(mmcUserEntity.getUserHead());
            userFriendDto.setRelationStatus(relationStatus);
            userFriendDtoList.add(userFriendDto);
        }
    }

    /**
     * 根据UserId查询用户所在的群组List，直接制作成用于网络间传输的Dto类
     * 只返回没有退出的群组List，像QQ一旦退出群组，不再显示该群组的聊天信息
     *
     * @param userId
     * @return
     */
    @Override
    public List<GroupsDto> queryUserGroupsList(String userId) {
        // user-group 关系
        List<MmcUserGroupEntity> userGroupList =
                mmcUserGroupService.list(new QueryWrapper<MmcUserGroupEntity>().eq("user_id", userId));
        // 正常群组Id
        List<String> normalGroupIdList = userGroupList.stream()
                .filter(userGroup -> userGroup.getRelationStatus() == 0)
                .map(MmcUserGroupEntity::getGroupId).collect(Collectors.toList());
        // 以拉黑的群组
        List<String> blockedGroupIdList = userGroupList.stream()
                .filter(userGroup -> userGroup.getRelationStatus() == 2)
                .map(MmcUserGroupEntity::getGroupId).collect(Collectors.toList());

        List<GroupsDto> groupsDtoList = new ArrayList<>();
        gIds2GDtoList(normalGroupIdList, groupsDtoList, 0);
        gIds2GDtoList(blockedGroupIdList, groupsDtoList, 2);
        return groupsDtoList;
    }

    private void gIds2GDtoList(List<String> groupIdList, List<GroupsDto> groupsDtoList, int relationStatus) {
        if (groupIdList == null || groupIdList.size() == 0) {
            return;
        }
        for (MmcGroupsEntity mmcGroupsEntity : mmcGroupsService.list(new QueryWrapper<MmcGroupsEntity>().in("group_id", groupIdList))) {
            GroupsDto groupsDto = new GroupsDto();
            BeanUtils.copyProperties(mmcGroupsEntity, groupsDto);
            groupsDto.setRelationStatus(relationStatus);
            groupsDtoList.add(groupsDto);
        }
    }

    /**
     * 获取userid对应用户的展开状态的聊天框，下次用户登录时也会展开聊天框。
     * 返回的聊天框可能是用户和自己好友的聊天，也可能是和陌生人的聊天
     *
     * @param userid
     * @return
     */
    @Override
    public List<MmcTalkBoxEntity> queryTalkBoxInfoList(String userid) {
        return mmcTalkBoxService.list(new QueryWrapper<MmcTalkBoxEntity>()
                .eq("user_id", userid)
                .eq("show_status", NettyConstants.TalkBoxShowStatus.OPEN.getCode()));
    }

    /**
     * 查询两个用户之间的聊天信息，双方发的都算，并按照时间进行排序
     *
     * @param userId
     * @param friendId
     * @return
     */
    @Override
    public List<MmcChatRecordEntity> queryUserFriendChatRecord(String userId, String friendId) {
        QueryWrapper<MmcChatRecordEntity> self2friend =
                new QueryWrapper<MmcChatRecordEntity>().eq("user_id", userId).eq("friend_id", friendId);
        return mmcChatRecordService
                .list(self2friend.or(qw -> qw.eq("user_id", friendId).eq("friend_id", userId)).orderByDesc("msg_date"));
    }

    /**
     * 查询一个群组中的所有聊天信息。
     *
     * @param userId
     * @param groupId
     */
    @Override
    public List<MmcChatRecordEntity> queryUserGroupChatRecord(String userId, String groupId) {
        return mmcChatRecordService
                .list(new QueryWrapper<MmcChatRecordEntity>().eq("friend_id", groupId));
    }

    /**
     * 异步执行聊天消息入库
     *
     * @param talkTypeCode 0-私聊消息 1-群聊消息
     * @return
     */
    @Override
    public CompletableFuture<Void> asyncAppendChatRecord(String senderId, String receiverId, String msgText, Date msgDate, Integer msgType, Integer talkTypeCode) {
        return CompletableFuture.runAsync(() -> addChatRecord(senderId, receiverId, msgText, msgDate, msgType, talkTypeCode), nettyThreadPoolExecutor);
    }

    /**
     * 聊天消息入库
     *
     * @param userId
     * @param talkId
     * @param msgText
     * @param msgDate
     * @param msgType
     * @param talkTypeCode
     */
    private void addChatRecord(String userId, String talkId, String msgText, Date msgDate, Integer msgType, Integer talkTypeCode) {
        MmcChatRecordEntity chatRecord = new MmcChatRecordEntity();
        chatRecord.setUserId(userId);  // 发送者Id
        chatRecord.setFriendId(talkId);  // 群组Id
        chatRecord.setMsgContent(msgText);  // 消息内容
        chatRecord.setMsgType(msgType);  // 文字/图片
        chatRecord.setMsgDate(msgDate);  // 发送时间
        chatRecord.setTalkType(talkTypeCode);  //
        chatRecord.setCreateTime(new Date());
        chatRecord.setUpdateTime(new Date());
        mmcChatRecordService.save(chatRecord);
    }

    /**
     * 异步执行聊天框入库
     *
     * @return
     */
    @Override
    public CompletableFuture<Void> asyncAppendTalkBox(String userId, String talkId, Integer talkTypeCode) {
        return CompletableFuture.runAsync(() -> addTalkBoxInfo(userId, talkId, talkTypeCode), nettyThreadPoolExecutor);
    }

    /**
     * 添加聊天框
     *
     * @param userId       发送者ID
     * @param friendUserId 接受者Id
     * @param talkType     类型 0-私聊 1-群聊
     */
    @Override
    public void addTalkBoxInfo(String userId, String friendUserId, Integer talkType) {
        // 还是先检查，如果已经存在聊天框且为展开模式则直接返回
        MmcTalkBoxEntity existedOne =
                mmcTalkBoxService.getOne(new QueryWrapper<MmcTalkBoxEntity>().eq("user_id", userId).eq("talk_id", friendUserId));
        if (existedOne == null) {
            MmcTalkBoxEntity talkBoxEntity = new MmcTalkBoxEntity();
            talkBoxEntity.setUserId(userId);
            talkBoxEntity.setTalkId(friendUserId);
            talkBoxEntity.setTalkType(talkType);
            talkBoxEntity.setShowStatus(NettyConstants.TalkBoxShowStatus.OPEN.getCode());
            talkBoxEntity.setCreateTime(new Date());
            talkBoxEntity.setUpdateTime(new Date());
            mmcTalkBoxService.save(talkBoxEntity);
        } else if (existedOne.getShowStatus().equals(NettyConstants.TalkBoxShowStatus.STACK.getCode())) {
            existedOne.setShowStatus(NettyConstants.TalkBoxShowStatus.OPEN.getCode());
            mmcTalkBoxService.updateById(existedOne);
        }
    }

    /**
     * 根据条件搜索好友，直接制作成UserDto
     *
     * @param selfId
     * @param searchKey
     * @return
     */
    @Override
    public List<UserDto> querySearchFriendList(String selfId, String searchKey) {
        List<UserDto> searchResultList = new ArrayList<>();
        QueryWrapper<MmcUserEntity> queryWrapper = new QueryWrapper<MmcUserEntity>().select("user_id", "user_nickname", "user_head");
        queryWrapper.like("user_id", searchKey).or(wrapper -> {
            wrapper.like("user_nickname", searchKey);
        });
        queryWrapper.and(wrapper -> {
            wrapper.ne("user_id", selfId);
        });
        queryWrapper.orderByDesc("id");
        queryWrapper.last("LIMIT 10");
        List<MmcUserEntity> searchFriendList = mmcUserService.list(queryWrapper);
        for (MmcUserEntity searchFriend : searchFriendList) {
            UserDto userDto = new UserDto(searchFriend.getUserId(), searchFriend.getUserNickname(), searchFriend.getUserHead());
            MmcUserFriendEntity relation =
                    mmcUserFriendService.getOne(new QueryWrapper<MmcUserFriendEntity>()
                            .eq("user_id", selfId).eq("user_friend_id", searchFriend.getUserId()));
            // 对已经添加的好友进行标记
            if (relation != null) {
                userDto.setStatus(2);
            }else{
                userDto.setStatus(1);
            }
            searchResultList.add(userDto);
        }
        return searchResultList;
    }
}
